#include <GL/glut.h>
#include "DrawBall.h"

int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(800,800);
    // glutInitWindowPosition(770, 400);
    glutCreateWindow("Jumping Ball");
    glutDisplayFunc(onRenderScene);
    // 设置尺寸改变回调
    glutReshapeFunc(onChangeSize);
    // 设置空闲函数
    glutIdleFunc(idle);
    // 初始化
    inital();
    // 设置时间函数
    glutTimerFunc(deltaMsec, onTimeChange, 1);
    SetupLights();
    glutMainLoop();

    return 0;
}

/**
 * 时间回调函数 每deltaMsec毫秒执行一次
 * 
 **/
void onTimeChange(int value)
{

    // 遇到边界则速度取反
    if (ball.getEdgeLeft() <= 0 || ball.getEdgeRight() >= windowWidth)    
    {
        ball.x_velocity = -ball.x_velocity;
    }
    if (ball.getEdgeButtom() <= 0 || ball.getEdgeTop() >= windowHeight)
    {
        ball.y_velocity = -ball.y_velocity;
    }
    // y方向存在加速度速度会发生变化，所以将更新前的速度存起来
    GLdouble yVelocityOld = ball.y_velocity;
    // 更新y方向速度 v = v + g*t
    ball.y_velocity += GRAVITY_ACCE * (deltaMsec / 1000.0);
    // x方向为匀速直线运动 delta_s = v*t
    ball.position.x += (deltaMsec * ball.x_velocity) / 1000.0;
    // y方向为匀变速直线运动 delta_s = v*t + 1/2 * g * t^2 = (v + g*t/2 )*t
    ball.position.y += (yVelocityOld + GRAVITY_ACCE *(deltaMsec / 1000.0) / 2)
                        * (deltaMsec / 1000.0);

    glutTimerFunc(deltaMsec, onTimeChange, 1);
}
/**
 * 尺寸改变回调
 * 
 * */
void onChangeSize(GLsizei w, GLsizei h)
{
    if (h == 0)
        h = 1;
    // 设置视区尺寸
    glViewport(0, 0, w, h);
    // 重置坐标系统,使投影变换复位
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    GLdouble edgeRight;
    GLdouble edgeTop;

    if (w <= h)
    {
        edgeRight = windowWidth;
        edgeTop = windowHeight * h / w;
    }
    else
    {
        edgeRight = windowWidth * w / h;
        edgeTop = windowHeight;
    }
    // 建立修剪空间的范围
    glOrtho(0, edgeRight, 0, edgeTop, 100, -100);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
/**
 * 初始化函数
 * 
 * */
void inital()
{
    // 定义窗体尺寸
    windowWidth = WINDOW_SIZE;
    windowHeight = WINDOW_SIZE;
    // 球体半径
    ballRadius = BALLRADIUS;
    // xy初速度
    yInitalSpeed = 0;

#if FREE_FALL
    xInitalSpeed = 0; // 自由落体
    ball = Sphere(Point(windowWidth / 2, windowHeight / 4 + windowHeight / 2), ballRadius, xInitalSpeed, yInitalSpeed); 
#else
    xInitalSpeed = 40; //沿直线跳动
    ball = Sphere(Point(ballRadius*2, windowHeight / 4 ), ballRadius, xInitalSpeed, yInitalSpeed);
#endif

    deltaMsec =10;

    glClearColor(1, 1, 1, 1);
}

/**
 * 渲染回调函数
 * 
 * */
void onRenderScene(void)
{

    // 使用当前颜色清空缓冲区,即设定背景颜色
    glClear(GL_COLOR_BUFFER_BIT);
    // 设定画笔颜色
    glColor3f(76.0/255, 180.0/255, 231.0/255);
    // 复原坐标系
    glLoadIdentity();
    // 平移坐标系
    glTranslatef(ball.position.x, ball.position.y, 0);
    // 画球
    glutSolidSphere(ball.radius, 50, 50);

    //清空命令缓冲区并交换帧缓存
    glutSwapBuffers();
}
void idle(void) //空闲函数
{
    glutPostRedisplay();
}
/**
 * 开启光照
 * */
void SetupLights()
{
    GLfloat ambientLight[] = {0.2f, 0.2f, 0.2f, 1.0f};  //环境光
    GLfloat diffuseLight[] = {0.9f, 0.9f, 0.9f, 1.0f};  //漫反射
    GLfloat specularLight[] = {1.0f, 1.0f, 1.0f, 1.0f}; //镜面光
    GLfloat lightPos[] = {0.0f,WINDOW_SIZE, -WINDOW_SIZE, 2.0f};    //光源位置 定义为左上角

    glEnable(GL_LIGHTING);                            //打开光照
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);   //设置环境光源
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);   //设置漫反射光源
    glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight); //设置镜面光源
    glLightfv(GL_LIGHT0, GL_POSITION, lightPos);      //设置灯光位置
    glEnable(GL_LIGHT0);                              //打开第一个灯光

    glEnable(GL_COLOR_MATERIAL);                        //使能跟踪材料颜色
    glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);  //指定材料着色的面
    glMaterialfv(GL_FRONT, GL_SPECULAR, specularLight); //指定材料对镜面光的反应
    glMateriali(GL_FRONT, GL_SHININESS, 100);           //指定反射系数
}